package com.webex.ta.hydra.gui.table;

import com.webex.ta.hydra.core.Command;
import com.webex.ta.hydra.gui.action.InsertAction;
import com.webex.ta.hydra.util.HydraUtils;

import javax.swing.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.Vector;

/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-9-1
 * Time: 12:08:15
 */
public class HydraTableTransferHandler extends TransferHandler {
    private HydraTable table;

    public HydraTableTransferHandler(HydraTable table) {
        this.table = table;
    }

    @Override
    public boolean canImport(TransferSupport support) {
        HydraTableModel tableModel = table.getModel();
        try {
            Object o = support.getTransferable().getTransferData(DataFlavor.stringFlavor);
            if (o instanceof int[]) {
                int[] selectedRows = (int[]) o;
                JTable.DropLocation dl = (JTable.DropLocation) support.getDropLocation();

                for (int row : selectedRows) {
                    if (row == dl.getRow())
                        return false;

                    Command cmd = tableModel.getCommandAt(row);
                    if (dl.getRow() < tableModel.getRowCount()) {
                        Command current = tableModel.getCommandAt(dl.getRow());
                        if (current.isDescentOf(cmd)) {
                            return false;
                        }
                        if (!HydraUtils.isController(current) && !dl.isInsertRow()) {
                            return false;
                        }
                    }
                }
            }
        } catch (UnsupportedFlavorException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    @Override
    protected Transferable createTransferable(JComponent c) {
        return new HydraTableTransferable();
    }

    @Override
    public int getSourceActions(JComponent c) {
        return MOVE;
    }

    @Override
    public boolean importData(TransferSupport support) {
        if (!canImport(support))
            return false;
        if (support.isDrop()) {
            JTable.DropLocation dl = (JTable.DropLocation) support.getDropLocation();
            if (dl.isInsertRow()) {
                insertSelectedTo(dl.getRow());
            } else {
                addSelectedTo(dl.getRow());
            }
            return true;
        }
        return false;
    }

    private void addSelectedTo(int row) {
        HydraTableModel tableModel = table.getModel();
        int[] selection = table.getSelectedRows();
        Command parent = tableModel.getCommandAt(row);
        Vector<Command> todo = new Vector<Command>();
        for (int i : selection) {
            todo.add(tableModel.getCommandAt(i));
        }

        // filter children
        // if a parent and one of its children are both selected
        // we only need to move the parent
        for (int i = 0; i < todo.size(); i++) {
            for (int j = todo.size() - 1; j >= 0; j--) {
                if (todo.get(j).isDescentOf(todo.get(i))) {
                    todo.remove(j);
                }
            }
        }

        for (Command cmd : todo) {
            tableModel.appendCommand(parent, cmd);
        }
        tableModel.fireTableDataChanged();
    }

    private void insertSelectedTo(int row) {
        HydraTableModel tableModel = table.getModel();
        int[] selection = table.getSelectedRows();
        for (int i = selection.length - 1; i >= 0; i--) {
            Command cmd = tableModel.getCommandAt(selection[i]);
            tableModel.removeCommand(cmd);
            if (row >= tableModel.getRowCount()) { // append to last
                InsertAction.insert(cmd, tableModel.getRowCount() - 1, true);
            } else { // insert before
                InsertAction.insert(cmd, row, false);
            }
        }
        tableModel.fireTableDataChanged();
    }
}
